package aventuraespacial;
//ale
import java.awt.Color;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Random;
import javax.swing.JFrame;
import java.awt.event.*;



/**
 * @author    woodoo
 */
@SuppressWarnings("serial")
public class EspacioExterior extends JFrame implements KeyListener, Runnable{
	 
	
	/**************************  CONSTANTES DE LA CLASE   **************************/
	
	
	static final int ANCHO_PANTALLA=800;
    static final int ALTO_PANTALLA=600;
    static final int VELOCIDAD_NAVE=20;
    
    
    static final int ANGULO_SUR=-270;
    static final int ANGULO_NORTE=-90;
    
    static final int VELOCIDAD_EXTRATERRESTRE=5;
    static final int VELOCIDAD_PODERES=3;
    
    static final int SLEEP_TIME_BUFFER=50;
    static final int TIEMPO_ENTRE_EXTRATERRESTRES=40;
    static final int TIEMPO_ENTRE_PODERES=180;
    
    static final int INTERVALO_GENERACION_PAQUETE =20;
    static final int VELOCIDAD_BALA_DEFAULT = 7;
    
    static final String NOMBRE_FONDO="espacio.png";
    
    static final int ANCHO_FONDO=514;
    static final int ALTO_FONDO=309;
    
    /**************************  ATRIBUTOS DE LA CLASE   **************************/
       
    
    private BufferedImage dobleBuffer;
    
    protected Graphics2D g2d;
    
    private AffineTransform identidad = new AffineTransform();
    
    private Thread hiloEspacial;
        
   
    private Nave nave;
        
    private ArrayList<Extraterrestre> extraterrestres;
    
    private ArrayList<Poder> poderes;
    
    private int tiempoNuevoExtraterrestre;
    
    private int radioDifcultad;
    
    private Image fondoEspacio;
    
        
    
   


	/**************************  CONSTRUCTOR DE LA CLASE   **************************/     
    
    
    public EspacioExterior(){   
    	super("Aventura Espacial");
    	//INSTANCIO LAS VARIABLES DEL JUEGO
    	nave= new Nave(600,300,VELOCIDAD_NAVE,ANGULO_NORTE); 
    	extraterrestres = new ArrayList<Extraterrestre>(); 
    	poderes = new ArrayList<Poder>();
    	//tiempoNuevoPoder=0;
    	tiempoNuevoExtraterrestre=0;
    	
    	//INICIALIZO EL JFRAME Y OBTENGO LOS DATOS PARA GRAFICAR
    	setSize(ANCHO_PANTALLA, ALTO_PANTALLA);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        dobleBuffer=  new BufferedImage(ANCHO_PANTALLA,ALTO_PANTALLA,BufferedImage.TYPE_INT_RGB);
        g2d=dobleBuffer.createGraphics();
        
        //AGREGO EL LECTOR DE TECLAS Y DIBUJO
        addKeyListener(this);
        identidad = new AffineTransform();
        
        //DATOS PARA LA CREACION DE PAQUETES
        radioDifcultad= 6;
        
        setFondoEspacio(cargarImagen(NOMBRE_FONDO));
        
        //INSTANCIA E INICIO EL THREAD
        hiloEspacial=new Thread(this);
        hiloEspacial.start();    
        
        
        
    }
    
    
    /**
	 * GUETTERS SETTERS
	 * @uml.property  name="extraterrestres"
	 */
    
    
    public ArrayList<Extraterrestre> getExtraterrestres() {
		return extraterrestres;
	}

	/**
	 * @param extraterrestres
	 * @uml.property  name="extraterrestres"
	 */
	public void setExtraterrestres(ArrayList<Extraterrestre> extraterrestres) {
		this.extraterrestres = extraterrestres;
	}
		
    /**
	 * @return
	 * @uml.property  name="poderes"
	 */
    public ArrayList<Poder> getPoderes() {
		return poderes;
	}

	/**
	 * @param poderes
	 * @uml.property  name="poderes"
	 */
	public void setPoderes(ArrayList<Poder> poderes) {
		this.poderes = poderes;
	}
	
	 public Image getFondoEspacio() {
			return fondoEspacio;
		}


		public void setFondoEspacio(Image fondoEspacio) {
			this.fondoEspacio = fondoEspacio;
		}

	/************************** METODOS DE CLASE *****************************************/	
	
	public void terminarJuego(){
		hiloEspacial=null;
	}

	
	private URL  getUrl(String nombreArchivo){
		
		URL url=null;
		try{
				url= this.getClass().getResource(nombreArchivo);
		}catch (Exception e){}
		return url;
	}
	
	public Image cargarImagen(String nombreArchivo){
		
		return Toolkit.getDefaultToolkit().getImage(getUrl(nombreArchivo));
	}
		
	
	/************************** RENDERIZADO Y PINTADO DEL DOBLEBUFFER **************************/
    
    
	
	public void paint(Graphics g){
    	
    	 /// EL PAINT SIMPLEMENTE DIBUJA EL DOBLE BUFFER EN EL FRAME 
    	 
    	render();
    	
    	g.drawImage(dobleBuffer,0,0,this);
        
    }       

	public void render(){
    	/*
    	 * EL RENDER GRAFICA TODO SOBRE EL DOBLE BUFFER QUE LUEGO SERA MOSTRADO EN EL REPAINT 
    	 * */
    	identidad= new AffineTransform();
    	g2d.setTransform(identidad);
    	g2d.setColor(Color.BLACK);
    	g2d.fill(new Rectangle (ANCHO_PANTALLA,ALTO_PANTALLA));
    	dibujarFondo(g2d);
    	dibujarNave(g2d);
    	dibujarBalas(g2d);
    	dibujarExtraterrestres(g2d);
    	dibujarPoderes(g2d);
    	dibujarDatos(g2d);
    }
	
	
	public void dibujarFondo(Graphics2D g){
		AffineTransform trans= new AffineTransform();
		trans.setTransform(identidad);
		//514x309 pixels =TAMAÑO FODO   800/514=X=1.5    600/309=Y=1.9
		trans.scale((float)ANCHO_PANTALLA/ANCHO_FONDO,(float)ALTO_PANTALLA/ALTO_FONDO);
		g.drawImage(getFondoEspacio(),trans,null);
	}
	
    public void dibujarNave(Graphics2D g){   			
    	
		nave.dibujar(g);		
	}
    
    
    public void dibujarDatos(Graphics2D g){
    	g.setColor(Color.WHITE);
    	g.drawString("Lifes: "+nave.getVidas()+" Vidas: "+nave.getSalud()+" X: "+nave.getX()+" Y: "+ nave.getY(),ANCHO_PANTALLA-230,ALTO_PANTALLA-20);
		g.drawString("Cant de balas: "+nave.cantBalas()+"  Cant de extraterrestres: "+
				extraterrestres.size() +"  Cant de Poderes: "+ poderes.size(),3,ALTO_PANTALLA-20);
		g.drawString("Cantidad Poderes Especiales: "+nave.getCantPoderesEspeciales() ,3,ALTO_PANTALLA-35);
    }
    
    
    public void dibujarBalas(Graphics2D g){
    	
    	Bala bala;
    	ArrayList<Bala> balas =nave.getListaBalas();
    	ListIterator<Bala> i= balas.listIterator();
    	while (i.hasNext()){
    		bala= i.next();
    		if (bala.isVivo()){
    			bala.dibujar(g);
    			
    		}    		
    	}   	
    }
    
    public void dibujarExtraterrestres (Graphics2D g){
    	Extraterrestre ex;
    	ArrayList<Extraterrestre> extra =getExtraterrestres();
    	ListIterator<Extraterrestre> i= extra.listIterator();
    	while (i.hasNext()){
    		ex = i.next();
    		if(ex.isVivo()){
    			ex.dibujar(g);
    		}
    	}
     }
    
    public void dibujarPoderes (Graphics2D g){
    	Poder power;
    	ArrayList<Poder> powers =getPoderes();
    	ListIterator<Poder> i= powers.listIterator();
    	while (i.hasNext()){
    		power = i.next();
    		if(power.isVivo()){
    			
    			power.dibujar(g);
    		}
    	}
    	
    }
    
    
 /************************** METODOS DE KEYPRES Y RELEASE KEY E IMPLEMENTACION*********************/
    
    
    @Override   
    public void keyTyped(KeyEvent e) {
    	
    }

    @Override
    public void keyPressed(KeyEvent e) {
    	
    	int teclaPresionada =e.getKeyCode();
    	presionarTeclas(teclaPresionada);
    }

    @Override
    public void keyReleased(KeyEvent e) {
    	int teclaPresionada =e.getKeyCode();
    	soltarTeclas(teclaPresionada);
    }
    
    public void presionarTeclas(int teclaPresionada){
    	switch (teclaPresionada) {
        
	        case KeyEvent.VK_UP:{//disminuyo velocidaY
	        	
	        	nave.direcciones[Nave.NORTE]=true;        	
	        } break;           
	
	        case KeyEvent.VK_DOWN:{//aumento velocidaY
	        	
	        	nave.direcciones[Nave.SUR]=true;
	        } break;
	        	
	        	
	        case KeyEvent.VK_LEFT: {//disminuyo velocidaX
	        	
	        	nave.direcciones[Nave.OESTE]=true;
	        } break;
	            
	
	        case KeyEvent.VK_RIGHT:{//aumento velocidaX
	        	
	        	nave.direcciones[Nave.ESTE]=true;
	        } break;
	        
	        case KeyEvent.VK_1:{
	        	
	        	nave.setModeloBala(new BalaFuego(1,1,VELOCIDAD_BALA_DEFAULT,ANGULO_NORTE));        	
	        } break;
	        
	        case KeyEvent.VK_2:{
	        	
	        	nave.setModeloBala(new BalaDoble(1,1,VELOCIDAD_BALA_DEFAULT,ANGULO_NORTE));
	        } break;
	        
	        case KeyEvent.VK_3:{
	        	
	        	
	        } break;
	        
	        case KeyEvent.VK_4:{
	        	
	        	nave.setModeloBala(new BalaTriple(1,1,VELOCIDAD_BALA_DEFAULT,ANGULO_NORTE));
	        } break;
	        
	        case KeyEvent.VK_SPACE:{
	        	
	        	nave.disparar();
	        } break;
    	
	        case KeyEvent.VK_SHIFT:{
	        	
	        	nave.dispararPoderEspecial();
	        } break;
	        
	        case KeyEvent.VK_E:{
	        	
	        	nave.setEscudo(true);
	        } break;
	        case KeyEvent.VK_B:{
	        	
	        	ObjetoEspacial.setBordesActivados(!ObjetoEspacial.isBordesActivados());
	        } break;
    	}
    
    }
    
    public void soltarTeclas(int teclaPresionada){
        	switch (teclaPresionada) {
            
	            case KeyEvent.VK_UP:{//disminuyo velocidaY
	            	
	            	nave.direcciones[Nave.NORTE]=false;
	            	
	            } break;
	            	
	               
	
	            case KeyEvent.VK_DOWN:{//aumento velocidaY
	            	
	            	nave.direcciones[Nave.SUR]=false;
	            } break;
	            	
	            	
	            case KeyEvent.VK_LEFT: {//disminuyo velocidaX
	            	
	            	nave.direcciones[Nave.OESTE]=false;
	            } break;
	                
	
	            case KeyEvent.VK_RIGHT:{//aumento velocidaX
	            	
	            	nave.direcciones[Nave.ESTE]=false;
	            } break;
        	}   
}

    	 
    
   /************************** THREAD PRINCIPAL DEL JUEGO**************************/

    

	@Override
	public void run() {
		
		Thread hiloActualExiste;
        hiloActualExiste= Thread.currentThread();
        
        int extraX=0,extraY=0;
        ObjetoEspacial.setBordesActivados(true);
        while (hiloActualExiste==hiloEspacial){           
          //TIEMPO_ENTRE_PODERES
        	           
           try{       	   
        	   tiempoNuevoExtraterrestre++;
        	   if (tiempoNuevoExtraterrestre>=TIEMPO_ENTRE_EXTRATERRESTRES){
        		   Random random= new Random();
        		   extraX =random.nextInt(ANCHO_PANTALLA-Extraterrestre.ANCHO_EXTRATERRESTRE);        		   
        		   extraY =random.nextInt(ALTO_PANTALLA/5)+Extraterrestre.ALTO_EXTRATERRESTRE;
        		   
        		   getExtraterrestres().add(new Extraterrestre(extraX,extraY,Extraterrestre.VELOCIDAD_EXTRATERRESTRE,ANGULO_SUR ));
        		   tiempoNuevoExtraterrestre=0;
        		   
        	   }
        	   
        	   
        	   actualizarNave();
        	   actualizarExtraterrestres();
        	   actualizarBalas();
        	   chequearColisiones();
        	   actualizarPoderes();
        	   borrarMuertos();
        	   
        	   Thread.sleep(SLEEP_TIME_BUFFER);
        	   
        	   repaint();
        	   
           }catch(Exception e){
        	   System.out.println("El Thread tiro una Exception!");
           }
           
                       
        }
		
	}
	
	
	
	/********************* COMIENZA ACTAULIZACION DE OBJETOS ESPACIALES  ********************/
	
	
	
	public void actualizarNave(){
		/**COMPRUEBO LA PERDIDA DE VIDA Y SALUD*/
		if(nave.getVidas()==0) terminarJuego();
		else if(nave.getSalud()==0){
				nave.setSalud(nave.getSaludMaxima());
				nave.setVidas(nave.getVidas()-1);
				nave.moverOringen();
				nave.setInmune(true);
				javax.swing.Timer timer = new javax.swing.Timer(3000, new ActionListener() {
			          public void actionPerformed(ActionEvent e) {
			        	  nave.setInmune(false);
			          }
			       });
				timer.setRepeats(false);
				
				timer.start();
		}
		
		if (nave.estaEnMovimiento()){
			nave.actualizarX();
			nave.actualizarY();
			
		}
		/**COMPRUEBO QUE LA NAVE NO SE VALLA FUERA DE PANTALLA*/
		
		//nave.setX(nave.getX()+nave.getVelocidasX());	
		if((nave.getX()+Nave.ANCHONAVE/2)>ANCHO_PANTALLA) nave.setX(ANCHO_PANTALLA-(Nave.ANCHONAVE/2));
		else if((nave.getX()-Nave.ANCHONAVE/2)<0) nave.setX(Nave.ANCHONAVE/2);
		
		//nave.setY(nave.getY()+nave.getVelocidadY());		
		if((nave.getY()+Nave.ALTONAVE/2)>ALTO_PANTALLA) nave.setY(ALTO_PANTALLA-Nave.ALTONAVE/2);
		else if((nave.getY()-Nave.ALTONAVE/2)<0) nave.setY(Nave.ALTONAVE/2);
	}
	
	
	public void actualizarExtraterrestres(){
		
		ArrayList<Extraterrestre> extra = getExtraterrestres();
		ListIterator<Extraterrestre> i = extra.listIterator();
		Extraterrestre ex;
		
		while (i.hasNext()){
			ex = i.next();
			
			//si esta fuera de pantalla lo mato			
			if (ex.fueraDePantalla()) ex.setVivo(false);			
			if (ex.isVivo()){/**Se mueve mediante COS SIN*/				
				ex.actualizarX();
				ex.actualizarY();				
			}			
		}
	}
	
	
	public void actualizarBalas(){
		/***
		 * MODIFICAR LAS BALAS PARA QUE SE MUEVAN POR ANGULO.
		 * */
		Bala balaAux=null;		
		
		ArrayList<Bala> listaBalas= nave.getListaBalas();
		 ListIterator<Bala> i =   listaBalas.listIterator();
		 while(i.hasNext()){
			 
			 balaAux= i.next();
			 if (balaAux.fueraDePantalla()) balaAux.setVivo(false);		 
			 
			 if (balaAux.isVivo()){/**Se mueve mediante COS SIN*/
				 balaAux.actualizarX();
				 balaAux.actualizarY();
			}		 
		 }	
	}
	
	
	public void actualizarPoderes(){
		
		ArrayList<Poder> powers = getPoderes();
		ListIterator<Poder> i = powers.listIterator();
		Poder power;
		while (i.hasNext()){
			power = i.next();			
			if (power.fueraDePantalla()) power.setVivo(false);				
			if (power.isVivo()){
				power.actualizarX();
				power.actualizarY();
			} 			
		}			
	}
	
		
	
	/********** CHEQUEO DE TODAS LAS COLISIONES POSIBLES ENTRE OBJETOS ESPACIALES*********/
	
	
	public void chequearColisiones(){
		
		
		ListIterator<Bala> itBalas= nave.getListaBalas().listIterator();
		
		Extraterrestre extraAux;
		Bala balaAux;
		Poder poderAux;
		
		while (itBalas.hasNext()){
			balaAux=itBalas.next();
			
			if (balaAux.isVivo()){

				Rectangle bodeBala = balaAux.getBordes();	
				
				ListIterator<Extraterrestre> itExtraterrestres= getExtraterrestres().listIterator();
					while (itExtraterrestres.hasNext()){
					/**CHEQUEO LAS COLISIONES ENTRE LA BALA Y TODOS LOS EXTRATERRESTRES EXISTENTENS**/
						extraAux=itExtraterrestres.next();
						
						if( extraAux.isVivo()){
							if((extraAux.getBordes().contains(bodeBala)) ||  (extraAux.getBordes().intersects(bodeBala))){
								balaAux.impactarCon(extraAux);
								
								generarPaqueteRandom(extraAux.getX(),extraAux.getY());
							}
						}										
					}					
					
				
			}		
		}
		
		if (nave.isVivo()){/**CHEQUEO COLISIONES ENTRE NAVE Y EXTRATERRESTRES, LE REDUCE VIDA A LA NAVE*/
			ListIterator<Extraterrestre> itExtraterrestres= getExtraterrestres().listIterator();
			if (!nave.hasInmunidad()){
				while (itExtraterrestres.hasNext()){
					extraAux=itExtraterrestres.next();
					if(extraAux.isVivo()){
						
						if(nave.hasEscudo()){
							if(nave.getBordeEscudo().intersects(extraAux.getBordes())){
								nave.setEscudo(false);
								extraAux.setVivo(false);
							}
							
						}
						else				
						if(nave.getBordes().intersects(extraAux.getBordes())){
							nave.setSalud(0);						
							extraAux.setVivo(false);
							
						}
						
						
					}
				}
			}
			/**CHEQUEO COLISIONES ENTRE NAVE Y PODERES*/
			ListIterator<Poder> itPoderes= getPoderes().listIterator();	
			while (itPoderes.hasNext()){
				
				poderAux=itPoderes.next();			
				if (poderAux.isVivo()){
					if(nave.getBordes().intersects(poderAux.getBordes())){
						poderAux.asignarPoder(nave);
						poderAux.setVivo(false);
					}					
				}				
			}			
		}		
	}
	
		
	/************ REMOCION DE AQUELLOS OBJETOS ESPACIALES QUE TENGAN FLAG DE NO VIVOS ***********/
	
	public void borrarMuertos(){
		
		
		/**SACO LAS BALAS MUERTAS*/
		ListIterator<Bala> itBalas = nave.getListaBalas().listIterator();
		Bala balaAux;
		while(itBalas.hasNext()){
			balaAux=itBalas.next();
			if (!balaAux.isVivo()) itBalas.remove();
		}
		
		/**SACO LOS EXTRATERRESTRES MUERTOS*/
		ListIterator<Extraterrestre> itExtra = getExtraterrestres().listIterator();
		Extraterrestre extra;
		while(itExtra.hasNext()){
			extra =itExtra.next();
			if(!extra.isVivo()) itExtra.remove();
		}
		
		
		
		/**SACO LOS PODERES MUERTOS*/
		ListIterator<Poder> itPoderes = getPoderes().listIterator();
		Poder poder;
		while(itPoderes.hasNext()){
			poder =itPoderes.next();
			if(!poder.isVivo()) itPoderes.remove();
		}
		
		
	}



	public void generarPaqueteRandom(double x, double y){
		/**AGARRA EL INTERVALO DE GENERACION, EJ 20, LUEGO TOMA LA MITAD, OSEA 10, EL RADIO SE MIDE
	     * A PARTIR DEL 10 , OSEA ( -R Y R  ) RESPECTO A 10, EN ESTE INTERVALO NO SE DA 
	     * NINGUN PAQUETE, ES DECIR A MEDIDA QUE AUMENTA EL RADIO, SERA MAS DIFICIL 
	     * OBTENER PODERES.! */
		
		Random random= new Random();	
		
		//numRandom =[1;20] 
		int numRandom= random.nextInt(EspacioExterior.INTERVALO_GENERACION_PAQUETE)+1;
		
		int mitad= Math.round(EspacioExterior.INTERVALO_GENERACION_PAQUETE/2);
		
		if ((numRandom<(mitad-this.radioDifcultad))||(numRandom>(mitad+this.radioDifcultad))){
			
			int angulo =45+random.nextInt(91);			
			numRandom= random.nextInt(5)+1;			
			switch(numRandom){				
			case 1:getPoderes().add(new Vida(x,y,VELOCIDAD_PODERES,angulo)); break;
			case 2:getPoderes().add(new PaqueteBalas(x, y, VELOCIDAD_PODERES, angulo,new BalaDoble(1,1,VELOCIDAD_BALA_DEFAULT,ANGULO_NORTE))); break;
			case 3:getPoderes().add(new PaqueteBalas(x, y, VELOCIDAD_PODERES, angulo,new BalaTriple(1,1,VELOCIDAD_BALA_DEFAULT,ANGULO_NORTE))); break;
			case 4:getPoderes().add(new PaqueteBalas(x, y, VELOCIDAD_PODERES, angulo,new BalaBarredora(1,1,VELOCIDAD_BALA_DEFAULT,ANGULO_NORTE))); break;
			case 5: getPoderes().add(new EscudoProtector(x,y,VELOCIDAD_PODERES,angulo)); break;
			}
			
		return;
		}
		
	}

}
